package com.lingjtx.common.influx.factory;

import com.lingjtx.common.core.util.StringUtil;
import com.lingjtx.common.influx.annotation.EnableInfluxMapperScan;
import com.lingjtx.common.influx.annotation.InfluxMapper;
import com.lingjtx.common.influx.client.InfluxSession;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.filter.AnnotationTypeFilter;

import java.util.Map;
import java.util.Objects;

/**
 * InfluxMapperScannerRegistrar 与 InfluxMapperScanner 功能一模一样，只是 mapper 加载方式不一样
 * InfluxMapperScannerRegistrar 是通过注解 EnableInfluxMapperScan 来扫描 xml 和 mapper 接口
 * InfluxMapperScanner 是通过 spring 配置文件加载
 */
public class InfluxMapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {

    private ResourceLoader resourceLoader;

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

        Map<String, Object> attrs = importingClassMetadata
                .getAnnotationAttributes(EnableInfluxMapperScan.class.getName());
        if (Objects.nonNull(attrs) && !attrs.isEmpty()) {
            String[] basePackages = (String[]) attrs.get("basePackages");
            String mapperLocations = (String) attrs.get("mapperLocations");

            // 1. 注册 InfluxSession Bean（如果未注册）
            if (!registry.containsBeanDefinition("influxSession")) {
                BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(InfluxSession.class);
                builder.addConstructorArgReference("influxQueryExecutor");
                builder.addConstructorArgValue(mapperLocations);
                registry.registerBeanDefinition("influxSession", builder.getBeanDefinition());
            }

            // 2. 扫描所有 @InfluxMapper 接口并注册为 FactoryBean
            ClassPathScanningCandidateComponentProvider scanner =
                    new ClassPathScanningCandidateComponentProvider(false) {
                        @Override
                        protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
                            return true; // 放开限制
                        }
                    };
            scanner.setResourceLoader(resourceLoader);
            scanner.addIncludeFilter(new AnnotationTypeFilter(InfluxMapper.class));

            for (String basePackage : basePackages) {
                for (BeanDefinition bd : scanner.findCandidateComponents(basePackage)) {
                    try {
                        String className = bd.getBeanClassName();
                        Class<?> clazz = Class.forName(className);
                        BeanDefinitionBuilder factoryBeanBuilder = BeanDefinitionBuilder
                                .genericBeanDefinition(InfluxMapperFactoryBean.class);
                        factoryBeanBuilder.addConstructorArgValue(clazz);
                        if (StringUtil.isNotEmpty(className)) {
                            registry.registerBeanDefinition(className, factoryBeanBuilder.getBeanDefinition());
                        }
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }
    }

    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }
}
